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
2 changes: 1 addition & 1 deletion cargo-auditable/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ auditable-serde = {version = "0.8.0", path = "../auditable-serde"}
miniz_oxide = {version = "0.8.0"}
serde_json = "1.0.57"
cargo_metadata = "0.18"
pico-args = { version = "0.5", features = ["eq-separator"] }
pico-args = { version = "0.5", features = ["eq-separator", "short-space-opt"] }
serde = "1.0.147"
wasm-gen = "0.1.4"

Expand Down
61 changes: 51 additions & 10 deletions cargo-auditable/src/rustc_arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub struct RustcArgs {
pub out_dir: Option<PathBuf>,
pub target: Option<String>,
pub print: Vec<String>,
pub codegen: Vec<String>,
}

impl RustcArgs {
Expand All @@ -35,6 +36,29 @@ impl RustcArgs {
}
result
}

/// Normally `rustc` uses a C compiler such as `cc` or `clang` as linker,
/// and arguments to the actual linker need to be passed prefixed with `-Wl,`.
/// But it is possible to configure Cargo and rustc to call a linker directly,
/// and the breakage it causes is subtle enough that people just roll with it
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😂

/// and complain when cargo-auditable doesn't support this configuration:
/// <https://github.com/rust-secure-code/cargo-auditable/issues/202>
///
/// This function can tell you if a bare linker is in use
/// and whether you need to prepend `-Wl,` or not.
///
/// Such setups are exceptionally rare and frankly it's a misconfiguration
/// that will break more than just `cargo auditable`, but I am feeling generous.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙏

pub fn bare_linker(&self) -> bool {
let linker_flag = self.codegen.iter().find(|s| s.starts_with("linker="));
if let Some(linker_flag) = linker_flag {
let linker = linker_flag.strip_prefix("linker=").unwrap();
if linker.ends_with("ld") {
return true;
}
}
false
}
}

impl RustcArgs {
Expand Down Expand Up @@ -62,6 +86,7 @@ impl RustcArgs {
})?,
target: parser.opt_value_from_str("--target")?,
print: parser.values_from_str("--print")?,
codegen: parser.values_from_str("-C")?,
})
}
}
Expand Down Expand Up @@ -147,16 +172,7 @@ mod tests {

#[test]
fn multiple_emit_values() {
let raw_rustc_args = vec![
"--emit=dep-info,link",
"--emit",
"llvm-bc",
// end of interesting args, start of boilerplate
"--crate-name",
"foobar",
"--out-dir",
"/foo/bar",
];
let raw_rustc_args = vec!["--emit=dep-info,link", "--emit", "llvm-bc"];
let raw_rustc_args: Vec<OsString> = raw_rustc_args.into_iter().map(|s| s.into()).collect();
let mut args = RustcArgs::from_vec(raw_rustc_args).unwrap();

Expand All @@ -168,4 +184,29 @@ mod tests {

assert_eq!(args.emit, expected)
}

#[test]
fn detect_bare_linker() {
let raw_rustc_args = vec!["-C", "linker=rust-lld"];
let raw_rustc_args: Vec<OsString> = raw_rustc_args.into_iter().map(|s| s.into()).collect();
let args = RustcArgs::from_vec(raw_rustc_args).unwrap();
assert!(args.bare_linker());
}

#[test]
fn multiple_codegen_options() {
let raw_rustc_args = vec!["-Clinker=clang", "-C", "link-arg=-fuse-ld=/usr/bin/mold"];
let raw_rustc_args: Vec<OsString> = raw_rustc_args.into_iter().map(|s| s.into()).collect();
let mut args = RustcArgs::from_vec(raw_rustc_args).unwrap();

let expected = vec!["linker=clang", "link-arg=-fuse-ld=/usr/bin/mold"];
let mut expected: Vec<String> = expected.into_iter().map(|s| s.into()).collect();

args.codegen.sort();
expected.sort();

assert_eq!(args.codegen, expected);

assert!(!args.bare_linker());
}
}
16 changes: 14 additions & 2 deletions cargo-auditable/src/rustc_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ pub fn main(rustc_path: &OsStr) {
let filename = format!(
"{}_audit_data.o",
args.crate_name
.as_ref()
.expect("rustc command is missing --crate-name")
);
let path = args
.out_dir
.as_ref()
.expect("rustc command is missing --out-dir")
.join(filename);
std::fs::write(&path, file).expect("Unable to write output file");
Expand All @@ -57,13 +59,23 @@ pub fn main(rustc_path: &OsStr) {
command.arg(linker_command);
// Prevent the symbol from being removed as unused by the linker
if is_apple(&target_info) {
command.arg("-Clink-arg=-Wl,-u,_AUDITABLE_VERSION_INFO");
if args.bare_linker() {
command.arg("-Clink-arg=-u,_AUDITABLE_VERSION_INFO");
} else {
command.arg("-Clink-arg=-Wl,-u,_AUDITABLE_VERSION_INFO");
}
} else if is_msvc(&target_info) {
command.arg("-Clink-arg=/INCLUDE:AUDITABLE_VERSION_INFO");
} else if is_wasm(&target_info) {
// We don't emit the symbol name in WASM, so nothing to do
} else {
command.arg("-Clink-arg=-Wl,--undefined=AUDITABLE_VERSION_INFO");
// Unrecognized platform, assume it to be unix-like
#[allow(clippy::collapsible_else_if)]
if args.bare_linker() {
command.arg("-Clink-arg=--undefined=AUDITABLE_VERSION_INFO");
} else {
command.arg("-Clink-arg=-Wl,--undefined=AUDITABLE_VERSION_INFO");
}
}
} else {
// create_binary_file() returned None, indicating an unsupported architecture
Expand Down
Loading