From f41ae64722ab8e501e2123018d1b0101db32442e Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Tue, 23 Mar 2021 11:22:33 +0800 Subject: [PATCH 1/2] Ignore proc-macro stdout to prevent IPC crash --- crates/proc_macro_api/src/msg.rs | 25 +++++++++++++------ .../rust-analyzer/tests/rust-analyzer/main.rs | 4 +++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/crates/proc_macro_api/src/msg.rs b/crates/proc_macro_api/src/msg.rs index 970f165edc3f..21e56cc831b0 100644 --- a/crates/proc_macro_api/src/msg.rs +++ b/crates/proc_macro_api/src/msg.rs @@ -77,13 +77,24 @@ impl Message for Request {} impl Message for Response {} fn read_json(inp: &mut impl BufRead) -> io::Result> { - let mut buf = String::new(); - inp.read_line(&mut buf)?; - buf.pop(); // Remove trailing '\n' - Ok(match buf.len() { - 0 => None, - _ => Some(buf), - }) + loop { + let mut buf = String::new(); + inp.read_line(&mut buf)?; + buf.pop(); // Remove trailing '\n' + + if buf.is_empty() { + return Ok(None); + } + + // Some ill behaved macro try to use stdout for debugging + // We ignore it here + if !buf.starts_with("{") { + log::error!("proc-macro tried to print : {}", buf); + continue; + } + + return Ok(Some(buf)); + } } fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> { diff --git a/crates/rust-analyzer/tests/rust-analyzer/main.rs b/crates/rust-analyzer/tests/rust-analyzer/main.rs index 19516de7b9aa..4442cbff6810 100644 --- a/crates/rust-analyzer/tests/rust-analyzer/main.rs +++ b/crates/rust-analyzer/tests/rust-analyzer/main.rs @@ -712,6 +712,10 @@ pub fn foo(_input: TokenStream) -> TokenStream { // We hard code the output here for preventing to use any deps let mut res = TokenStream::new(); + // ill behaved proc-macro will use the stdout + // we should ignore it + println!("I am bad guy"); + // impl Bar for Foo { fn bar() {} } let mut tokens = vec![t!("impl"), t!("Bar"), t!("for"), t!("Foo")]; let mut fn_stream = TokenStream::new(); From 79f583ed6622be591886f99974766a3aeda39182 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Wed, 24 Mar 2021 03:47:08 +0800 Subject: [PATCH 2/2] Improve message usage in proc-macro Reuse storage for the buffer send to child process of proc-macro. --- crates/proc_macro_api/src/msg.rs | 12 ++++++++---- crates/proc_macro_api/src/process.rs | 7 +++++-- crates/proc_macro_srv/src/cli.rs | 7 ++++--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/crates/proc_macro_api/src/msg.rs b/crates/proc_macro_api/src/msg.rs index 21e56cc831b0..f525df1525d5 100644 --- a/crates/proc_macro_api/src/msg.rs +++ b/crates/proc_macro_api/src/msg.rs @@ -55,8 +55,8 @@ pub enum ErrorCode { } pub trait Message: Serialize + DeserializeOwned { - fn read(inp: &mut impl BufRead) -> io::Result> { - Ok(match read_json(inp)? { + fn read(inp: &mut impl BufRead, buf: &mut String) -> io::Result> { + Ok(match read_json(inp, buf)? { None => None, Some(text) => { let mut deserializer = serde_json::Deserializer::from_str(&text); @@ -76,9 +76,13 @@ pub trait Message: Serialize + DeserializeOwned { impl Message for Request {} impl Message for Response {} -fn read_json(inp: &mut impl BufRead) -> io::Result> { +fn read_json<'a>( + inp: &mut impl BufRead, + mut buf: &'a mut String, +) -> io::Result> { loop { - let mut buf = String::new(); + buf.clear(); + inp.read_line(&mut buf)?; buf.pop(); // Remove trailing '\n' diff --git a/crates/proc_macro_api/src/process.rs b/crates/proc_macro_api/src/process.rs index 30bb1b687b1c..99d05aef3764 100644 --- a/crates/proc_macro_api/src/process.rs +++ b/crates/proc_macro_api/src/process.rs @@ -90,8 +90,10 @@ impl ProcMacroProcessSrv { fn client_loop(task_rx: Receiver, mut process: Process) { let (mut stdin, mut stdout) = process.stdio().expect("couldn't access child stdio"); + let mut buf = String::new(); + for Task { req, result_tx } in task_rx { - match send_request(&mut stdin, &mut stdout, req) { + match send_request(&mut stdin, &mut stdout, req, &mut buf) { Ok(res) => result_tx.send(res).unwrap(), Err(err) => { log::error!( @@ -152,7 +154,8 @@ fn send_request( mut writer: &mut impl Write, mut reader: &mut impl BufRead, req: Request, + buf: &mut String, ) -> io::Result> { req.write(&mut writer)?; - Response::read(&mut reader) + Response::read(&mut reader, buf) } diff --git a/crates/proc_macro_srv/src/cli.rs b/crates/proc_macro_srv/src/cli.rs index d428b9567531..bc48f1c436cf 100644 --- a/crates/proc_macro_srv/src/cli.rs +++ b/crates/proc_macro_srv/src/cli.rs @@ -6,8 +6,9 @@ use std::io; pub fn run() -> io::Result<()> { let mut srv = ProcMacroSrv::default(); + let mut buf = String::new(); - while let Some(req) = read_request()? { + while let Some(req) = read_request(&mut buf)? { let res = match req { msg::Request::ListMacro(task) => srv.list_macros(&task).map(msg::Response::ListMacro), msg::Request::ExpansionMacro(task) => { @@ -30,8 +31,8 @@ pub fn run() -> io::Result<()> { Ok(()) } -fn read_request() -> io::Result> { - msg::Request::read(&mut io::stdin().lock()) +fn read_request(buf: &mut String) -> io::Result> { + msg::Request::read(&mut io::stdin().lock(), buf) } fn write_response(msg: msg::Response) -> io::Result<()> {