8159: Ignore proc-macro stdout to prevent IPC crash r=edwin0cheng a=edwin0cheng

fixes  #7954

r? @flodiebold 

Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
This commit is contained in:
bors[bot] 2021-03-23 20:06:44 +00:00 committed by GitHub
commit d702f10fb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 38 additions and 15 deletions

View File

@ -55,8 +55,8 @@ pub enum ErrorCode {
}
pub trait Message: Serialize + DeserializeOwned {
fn read(inp: &mut impl BufRead) -> io::Result<Option<Self>> {
Ok(match read_json(inp)? {
fn read(inp: &mut impl BufRead, buf: &mut String) -> io::Result<Option<Self>> {
Ok(match read_json(inp, buf)? {
None => None,
Some(text) => {
let mut deserializer = serde_json::Deserializer::from_str(&text);
@ -76,14 +76,29 @@ pub trait Message: Serialize + DeserializeOwned {
impl Message for Request {}
impl Message for Response {}
fn read_json(inp: &mut impl BufRead) -> io::Result<Option<String>> {
let mut buf = String::new();
inp.read_line(&mut buf)?;
buf.pop(); // Remove trailing '\n'
Ok(match buf.len() {
0 => None,
_ => Some(buf),
})
fn read_json<'a>(
inp: &mut impl BufRead,
mut buf: &'a mut String,
) -> io::Result<Option<&'a String>> {
loop {
buf.clear();
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<()> {

View File

@ -90,8 +90,10 @@ impl ProcMacroProcessSrv {
fn client_loop(task_rx: Receiver<Task>, 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<Option<Response>> {
req.write(&mut writer)?;
Response::read(&mut reader)
Response::read(&mut reader, buf)
}

View File

@ -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<Option<msg::Request>> {
msg::Request::read(&mut io::stdin().lock())
fn read_request(buf: &mut String) -> io::Result<Option<msg::Request>> {
msg::Request::read(&mut io::stdin().lock(), buf)
}
fn write_response(msg: msg::Response) -> io::Result<()> {

View File

@ -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();