Return error when external command core dumped (#5908)

* Return error when external command core dumped

Fixes #5903

Signed-off-by: nibon7 <nibon7@163.com>

* Use signal-hook to get signal name

Signed-off-by: nibon7 <nibon7@163.com>

* Fix comment

Signed-off-by: nibon7 <nibon7@163.com>
This commit is contained in:
nibon7 2022-07-01 21:58:21 +08:00 committed by GitHub
parent 6dde231dde
commit 5d00ecef56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 0 deletions

1
Cargo.lock generated
View File

@ -2630,6 +2630,7 @@ dependencies = [
"serde_yaml",
"sha2 0.10.2",
"shadow-rs",
"signal-hook",
"sqlparser",
"strip-ansi-escapes",
"sysinfo 0.23.13",

View File

@ -91,6 +91,7 @@ sqlparser = { version = "0.16.0", features = ["serde"], optional = true }
[target.'cfg(unix)'.dependencies]
umask = "2.0.0"
users = "0.11.0"
signal-hook = { version = "0.3.14", default-features = false }
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies.trash]
version = "2.1.3"

View File

@ -194,6 +194,9 @@ impl ExternalCommand {
let (stderr_tx, stderr_rx) = mpsc::sync_channel(OUTPUT_BUFFERS_IN_FLIGHT);
let (exit_code_tx, exit_code_rx) = mpsc::channel();
#[cfg(unix)]
let (exit_status_tx, exit_status_rx) = mpsc::channel();
std::thread::spawn(move || {
// If this external is not the last expression, then its output is piped to a channel
// and we create a ListStream that can be consumed
@ -283,6 +286,9 @@ impl ExternalCommand {
span,
)),
Ok(x) => {
#[cfg(unix)]
let _ = exit_status_tx.send(x);
if let Some(code) = x.code() {
let _ = exit_code_tx.send(Value::Int {
val: code as i64,
@ -304,6 +310,26 @@ impl ExternalCommand {
let stderr_receiver = ChannelReceiver::new(stderr_rx);
let exit_code_receiver = ValueReceiver::new(exit_code_rx);
#[cfg(unix)]
{
use signal_hook::low_level::signal_name;
use std::os::unix::process::ExitStatusExt;
use std::time::Duration;
// The receiver will block 100ms if there's no sender
if let Ok(status) = exit_status_rx.recv_timeout(Duration::from_millis(100)) {
if status.core_dumped() {
if let Some(sig) = status.signal().and_then(signal_name) {
return Err(ShellError::ExternalCommand(
format!("{sig} (core dumped)"),
"Child process core dumped".to_string(),
span,
));
}
}
}
}
Ok(PipelineData::ExternalStream {
stdout: if redirect_stdout {
Some(RawStream::new(