diff --git a/src/cargo/core/compiler/fingerprint.rs b/src/cargo/core/compiler/fingerprint.rs index 23e256db369..a75482e2da5 100644 --- a/src/cargo/core/compiler/fingerprint.rs +++ b/src/cargo/core/compiler/fingerprint.rs @@ -1980,11 +1980,14 @@ pub fn parse_rustc_dep_info(rustc_dep_info: &Path) -> CargoResult let rest = &line[env_dep_prefix.len()..]; let mut parts = rest.splitn(2, '='); let env_var = match parts.next() { - Some(s) => s.to_string(), + Some(s) => s, None => continue, }; - let env_val = parts.next().map(|s| s.to_string()); - ret.env.push((env_var, env_val)); + let env_val = match parts.next() { + Some(s) => Some(unescape_env(s)?), + None => None, + }; + ret.env.push((unescape_env(env_var)?, env_val)); } else if let Some(pos) = line.find(": ") { if found_deps { continue; @@ -2005,5 +2008,27 @@ pub fn parse_rustc_dep_info(rustc_dep_info: &Path) -> CargoResult } } } - Ok(ret) + return Ok(ret); + + // rustc tries to fit env var names and values all on a single line, which + // means it needs to escape `\r` and `\n`. The escape syntax used is "\n" + // which means that `\` also needs to be escaped. + fn unescape_env(s: &str) -> CargoResult { + let mut ret = String::with_capacity(s.len()); + let mut chars = s.chars(); + while let Some(c) = chars.next() { + if c != '\\' { + ret.push(c); + continue; + } + match chars.next() { + Some('\\') => ret.push('\\'), + Some('n') => ret.push('\n'), + Some('r') => ret.push('\r'), + Some(c) => bail!("unknown escape character `{}`", c), + None => bail!("unterminated escape character"), + } + } + Ok(ret) + } } diff --git a/tests/testsuite/freshness.rs b/tests/testsuite/freshness.rs index d14bae64098..26d898484fc 100644 --- a/tests/testsuite/freshness.rs +++ b/tests/testsuite/freshness.rs @@ -2493,6 +2493,7 @@ fn env_in_code_causes_rebuild() { r#" fn main() { println!("{:?}", option_env!("FOO")); + println!("{:?}", option_env!("FOO\nBAR")); } "#, ) @@ -2527,6 +2528,19 @@ fn env_in_code_causes_rebuild() { .env_remove("FOO") .with_stderr("[FINISHED][..]") .run(); + + let interesting = " #!$\nabc\r\\\t\u{8}\r\n"; + p.cargo("build").env("FOO", interesting).run(); + p.cargo("build") + .env("FOO", interesting) + .with_stderr("[FINISHED][..]") + .run(); + + p.cargo("build").env("FOO\nBAR", interesting).run(); + p.cargo("build") + .env("FOO\nBAR", interesting) + .with_stderr("[FINISHED][..]") + .run(); } #[cargo_test]