Use bytes, not strings, for stdio observers (#885)

Previously, the `CommandExecutor` attempted to decode its child
process's stdout and stderr as UTF-8 `String`s. This could fail
if the output was not UTF-8. However, the `Std{Out,Err}Observer`s
should probably be able to be used in such a situation - Consider
fuzzing `echo` with a random `BytesInput`.

The fix is to not decode the output, but rather directly store and
provide the bytes of stdout/stderr in the observers.
This commit is contained in:
Langston Barrett 2022-11-10 06:40:59 -05:00 committed by GitHub
parent 1486c204eb
commit 893f284482
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 24 additions and 23 deletions

View File

@ -1,5 +1,5 @@
//! The command executor executes a sub program for each run //! The command executor executes a sub program for each run
use alloc::{string::String, vec::Vec}; use alloc::vec::Vec;
use core::{ use core::{
fmt::{self, Debug, Formatter}, fmt::{self, Debug, Formatter},
marker::PhantomData, marker::PhantomData,
@ -335,21 +335,21 @@ where
}; };
if self.observers.observes_stderr() { if self.observers.observes_stderr() {
let mut stderr = String::new(); let mut stderr = Vec::new();
child.stderr.as_mut().ok_or_else(|| { child.stderr.as_mut().ok_or_else(|| {
Error::illegal_state( Error::illegal_state(
"Observer tries to read stderr, but stderr was not `Stdio::pipe` in CommandExecutor", "Observer tries to read stderr, but stderr was not `Stdio::pipe` in CommandExecutor",
) )
})?.read_to_string(&mut stderr)?; })?.read_to_end(&mut stderr)?;
self.observers.observe_stderr(&stderr); self.observers.observe_stderr(&stderr);
} }
if self.observers.observes_stdout() { if self.observers.observes_stdout() {
let mut stdout = String::new(); let mut stdout = Vec::new();
child.stdout.as_mut().ok_or_else(|| { child.stdout.as_mut().ok_or_else(|| {
Error::illegal_state( Error::illegal_state(
"Observer tries to read stdout, but stdout was not `Stdio::pipe` in CommandExecutor", "Observer tries to read stdout, but stdout was not `Stdio::pipe` in CommandExecutor",
) )
})?.read_to_string(&mut stdout)?; })?.read_to_end(&mut stdout)?;
self.observers.observe_stdout(&stdout); self.observers.observe_stdout(&stdout);
} }

View File

@ -151,13 +151,13 @@ where
} }
/// Runs `observe_stdout` for all stdout observers in the list /// Runs `observe_stdout` for all stdout observers in the list
fn observe_stdout(&mut self, stdout: &str) { fn observe_stdout(&mut self, stdout: &[u8]) {
self.primary.as_mut().observe_stderr(stdout); self.primary.as_mut().observe_stderr(stdout);
self.secondary.as_mut().observe_stderr(stdout); self.secondary.as_mut().observe_stderr(stdout);
} }
/// Runs `observe_stderr` for all stderr observers in the list /// Runs `observe_stderr` for all stderr observers in the list
fn observe_stderr(&mut self, stderr: &str) { fn observe_stderr(&mut self, stderr: &[u8]) {
self.primary.as_mut().observe_stderr(stderr); self.primary.as_mut().observe_stderr(stderr);
self.secondary.as_mut().observe_stderr(stderr); self.secondary.as_mut().observe_stderr(stderr);
} }

View File

@ -106,13 +106,13 @@ where
/// To use this, always return `true` from `observes_stdout` /// To use this, always return `true` from `observes_stdout`
#[inline] #[inline]
#[allow(unused_variables)] #[allow(unused_variables)]
fn observe_stdout(&mut self, stdout: &str) {} fn observe_stdout(&mut self, stdout: &[u8]) {}
/// React to new `stderr` /// React to new `stderr`
/// To use this, always return `true` from `observes_stderr` /// To use this, always return `true` from `observes_stderr`
#[inline] #[inline]
#[allow(unused_variables)] #[allow(unused_variables)]
fn observe_stderr(&mut self, stderr: &str) {} fn observe_stderr(&mut self, stderr: &[u8]) {}
} }
/// Defines the observer type shared across traits of the type. /// Defines the observer type shared across traits of the type.
@ -155,9 +155,9 @@ where
fn observes_stderr(&self) -> bool; fn observes_stderr(&self) -> bool;
/// Runs `observe_stdout` for all stdout observers in the list /// Runs `observe_stdout` for all stdout observers in the list
fn observe_stdout(&mut self, stdout: &str); fn observe_stdout(&mut self, stdout: &[u8]);
/// Runs `observe_stderr` for all stderr observers in the list /// Runs `observe_stderr` for all stderr observers in the list
fn observe_stderr(&mut self, stderr: &str); fn observe_stderr(&mut self, stderr: &[u8]);
} }
impl<S> ObserversTuple<S> for () impl<S> ObserversTuple<S> for ()
@ -205,12 +205,12 @@ where
/// Runs `observe_stdout` for all stdout observers in the list /// Runs `observe_stdout` for all stdout observers in the list
#[inline] #[inline]
#[allow(unused_variables)] #[allow(unused_variables)]
fn observe_stdout(&mut self, stdout: &str) {} fn observe_stdout(&mut self, stdout: &[u8]) {}
/// Runs `observe_stderr` for all stderr observers in the list /// Runs `observe_stderr` for all stderr observers in the list
#[inline] #[inline]
#[allow(unused_variables)] #[allow(unused_variables)]
fn observe_stderr(&mut self, stderr: &str) {} fn observe_stderr(&mut self, stderr: &[u8]) {}
} }
impl<Head, Tail, S> ObserversTuple<S> for (Head, Tail) impl<Head, Tail, S> ObserversTuple<S> for (Head, Tail)
@ -263,14 +263,14 @@ where
/// Runs `observe_stdout` for all stdout observers in the list /// Runs `observe_stdout` for all stdout observers in the list
#[inline] #[inline]
fn observe_stdout(&mut self, stdout: &str) { fn observe_stdout(&mut self, stdout: &[u8]) {
self.0.observe_stdout(stdout); self.0.observe_stdout(stdout);
self.1.observe_stdout(stdout); self.1.observe_stdout(stdout);
} }
/// Runs `observe_stderr` for all stderr observers in the list /// Runs `observe_stderr` for all stderr observers in the list
#[inline] #[inline]
fn observe_stderr(&mut self, stderr: &str) { fn observe_stderr(&mut self, stderr: &[u8]) {
self.0.observe_stderr(stderr); self.0.observe_stderr(stderr);
self.1.observe_stderr(stderr); self.1.observe_stderr(stderr);
} }
@ -991,10 +991,10 @@ pub mod pybind {
} }
#[inline] #[inline]
fn observe_stderr(&mut self, _: &str) {} fn observe_stderr(&mut self, _: &[u8]) {}
#[inline] #[inline]
fn observe_stdout(&mut self, _: &str) {} fn observe_stdout(&mut self, _: &[u8]) {}
} }
impl MatchName for PythonObserversTuple { impl MatchName for PythonObserversTuple {

View File

@ -269,8 +269,8 @@ where
} }
/// Do nothing on new `stderr` /// Do nothing on new `stderr`
fn observe_stderr(&mut self, stderr: &str) { fn observe_stderr(&mut self, stderr: &[u8]) {
self.parse_asan_output(stderr); self.parse_asan_output(&String::from_utf8_lossy(stderr));
} }
} }

View File

@ -3,6 +3,7 @@
//! For example, they are supported on the [`crate::executors::CommandExecutor`]. //! For example, they are supported on the [`crate::executors::CommandExecutor`].
use alloc::string::String; use alloc::string::String;
use std::vec::Vec;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -15,7 +16,7 @@ pub struct StdOutObserver {
/// The name of the observer. /// The name of the observer.
pub name: String, pub name: String,
/// The stdout of the target during its last execution. /// The stdout of the target during its last execution.
pub stdout: Option<String>, pub stdout: Option<Vec<u8>>,
} }
/// An observer that captures stdout of a target. /// An observer that captures stdout of a target.
@ -37,7 +38,7 @@ where
} }
/// React to new `stdout` /// React to new `stdout`
fn observe_stdout(&mut self, stdout: &str) { fn observe_stdout(&mut self, stdout: &[u8]) {
self.stdout = Some(stdout.into()); self.stdout = Some(stdout.into());
} }
} }
@ -55,7 +56,7 @@ pub struct StdErrObserver {
/// The name of the observer. /// The name of the observer.
pub name: String, pub name: String,
/// The stderr of the target during its last execution. /// The stderr of the target during its last execution.
pub stderr: Option<String>, pub stderr: Option<Vec<u8>>,
} }
/// An observer that captures stderr of a target. /// An observer that captures stderr of a target.
@ -77,7 +78,7 @@ where
} }
/// React to new `stderr` /// React to new `stderr`
fn observe_stderr(&mut self, stderr: &str) { fn observe_stderr(&mut self, stderr: &[u8]) {
self.stderr = Some(stderr.into()); self.stderr = Some(stderr.into());
} }
} }