Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prefix async job output to prevent external corruption #28

Merged
merged 1 commit into from
Aug 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions async.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ _async_job() {
read -r -k 1 -p tok || exit 1

# Return output (<job_name> <return_code> <stdout> <duration> <stderr>).
print -r -n - ${(q)1} $ret ${(q)stdout} $duration
print -r -n - $'\0'${(q)1} $ret ${(q)stdout} $duration
} 2> >(stderr=$(cat) && print -r -n - " "${(q)stderr}$'\0')

# Unlock mutex by inserting a token.
Expand Down Expand Up @@ -245,13 +245,15 @@ async_process_results() {
if (( $#items == 5 )); then
items+=($has_next)
$callback "${(@)items}" # Send all parsed items to the callback.
(( num_processed++ ))
elif [[ -z $items ]]; then
# Empty items occur between results due to double-null ($'\0\0')
# caused by commands being both pre and suffixed with null.
else
# In case of corrupt data, invoke callback with *async* as job
# name, non-zero exit status and an error message on stderr.
$callback "async" 1 "" 0 "$0:$LINENO: error: bad format, got ${#items} items (${(q)items})" $has_next
fi

(( num_processed++ ))
done
done

Expand Down
10 changes: 6 additions & 4 deletions async_test.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ test__async_job_print_hi() {
local line
local -a out
line=$(_async_job print hi)
# Remove trailing null, parse, unquote and interpret as array.
line=$line[1,$#line-1]
# Remove leading/trailing null, parse, unquote and interpret as array.
line=$line[2,$#line-1]
out=("${(@Q)${(z)line}}")

coproc exit
Expand Down Expand Up @@ -396,8 +396,10 @@ test_async_flush_jobs() {
# TODO: Confirm that they no longer exist in the process tree.
local output
output="${(Q)$(ASYNC_DEBUG=1 async_flush_jobs test)}"
[[ $output = *'print_four 0 4'* ]] || {
t_error "want discarded output 'print_four 0 4' when ASYNC_DEBUG=1, got ${(Vq-)output}"
# NOTE(mafredri): First 'p' in print_four is lost when null-prefixing
# _async_job output.
[[ $output = *'rint_four 0 4'* ]] || {
t_error "want discarded output 'rint_four 0 4' when ASYNC_DEBUG=1, got ${(Vq-)output}"
}

# Check that the killed job did not produce output.
Expand Down