From 4c61f65906d88d524cabb7c9e207d2fa740c28ac Mon Sep 17 00:00:00 2001 From: itchyny Date: Mon, 10 Jul 2023 07:30:50 +0900 Subject: [PATCH] Fix --nul-output option to abort on a string containing NUL --- docs/content/manual/manual.yml | 1 + jq.1.prebuilt | 2 +- src/main.c | 11 +++++++++-- tests/shtest | 10 ++++++++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/content/manual/manual.yml b/docs/content/manual/manual.yml index ff68482a3d..c93b16f935 100644 --- a/docs/content/manual/manual.yml +++ b/docs/content/manual/manual.yml @@ -213,6 +213,7 @@ sections: Like `-r` but jq will print NUL instead of newline after each output. This can be useful when the values being output can contain newlines. + When the output value contains NUL, jq exits with non-zero code. * `-f filename` / `--from-file filename`: diff --git a/jq.1.prebuilt b/jq.1.prebuilt index 80933f748e..8a0372df2b 100644 --- a/jq.1.prebuilt +++ b/jq.1.prebuilt @@ -157,7 +157,7 @@ Like \fB\-r\fR but jq won\'t print a newline after each output\. \fB\-\-nul\-output\fR / \fB\-0\fR: . .IP -Like \fB\-r\fR but jq will print NUL instead of newline after each output\. This can be useful when the values being output can contain newlines\. +Like \fB\-r\fR but jq will print NUL instead of newline after each output\. This can be useful when the values being output can contain newlines\. When the output value contains NUL, jq exits with non\-zero code\. . .TP \fB\-f filename\fR / \fB\-\-from\-file filename\fR: diff --git a/src/main.c b/src/main.c index 48af5a31c1..0c854a0686 100644 --- a/src/main.c +++ b/src/main.c @@ -181,11 +181,18 @@ static int process(jq_state *jq, jv value, int flags, int dumpopts, int options) if ((options & RAW_OUTPUT) && jv_get_kind(result) == JV_KIND_STRING) { if (options & ASCII_OUTPUT) { jv_dumpf(jv_copy(result), stdout, JV_PRINT_ASCII); + ret = JQ_OK; + } else if ((options & RAW_NUL) && strlen(jv_string_value(result)) != (unsigned long)jv_string_length_bytes(jv_copy(result))) { + jv input_pos = jq_util_input_get_position(jq); + fprintf(stderr, "jq: error (at %s): %s\n", + jv_string_value(input_pos), "Cannot dump a string containing NUL with --nul-output option"); + jv_free(input_pos); + ret = JQ_ERROR_UNKNOWN; } else { priv_fwrite(jv_string_value(result), jv_string_length_bytes(jv_copy(result)), stdout, dumpopts & JV_PRINT_ISATTY); + ret = JQ_OK; } - ret = JQ_OK; jv_free(result); } else { if (jv_get_kind(result) == JV_KIND_FALSE || jv_get_kind(result) == JV_KIND_NULL) @@ -198,7 +205,7 @@ static int process(jq_state *jq, jv value, int flags, int dumpopts, int options) } if (!(options & RAW_NO_LF)) priv_fwrite("\n", 1, stdout, dumpopts & JV_PRINT_ISATTY); - if (options & RAW_NUL) + if ((options & RAW_NUL) && ret != JQ_ERROR_UNKNOWN) priv_fwrite("\0", 1, stdout, dumpopts & JV_PRINT_ISATTY); if (options & UNBUFFERED_OUTPUT) fflush(stdout); diff --git a/tests/shtest b/tests/shtest index d681ab45ad..cf35dbfc73 100755 --- a/tests/shtest +++ b/tests/shtest @@ -171,6 +171,16 @@ printf '["a", "b"]' | $JQ -0 .[] > $d/out 2>&1 cmp $d/out $d/expected printf '["a", "b"]' | $JQ --nul-output .[] > $d/out 2>&1 cmp $d/out $d/expected +printf '["a", "c\\u0000d", "b"]' | $JQ --nul-output .[] > $d/out 2>/dev/null +cmp $d/out $d/expected + +if printf '{"foo":"foo\\u0000bar"}' | $JQ --nul-output .foo; then + echo "Should exit error on string containing NUL with --nul-output" 1>&2 + exit 1 +elif [ $? -ne 5 ]; then + echo "Invalid error code" 1>&2 + exit 1 +fi ## Test streaming parser