dash:私のスクリプトにバックティックが含まれていませんが、「構文エラー:バックティック置換のEOF」エラーが発生するのはなぜですか?

dash:私のスクリプトにバックティックが含まれていませんが、「構文エラー:バックティック置換のEOF」エラーが発生するのはなぜですか?
#!/bin/sh --

for set_trap_sig in HUP INT QUIT ALRM TERM; do
    trap -- '
        trap -- - '"${set_trap_sig:?}"' EXIT || exit "$?"
        kill -s '"${set_trap_sig:?}"' -- "$$" || exit "$?"' "$set_trap_sig"
done

sleep 15 || exit "$?"

SIGINTをスクリプトに送信すると、これが発生します。

user@hostname:/tmp$ ./script.sh
^C./script.sh: 3: ./script.sh: Syntax error: EOF in backquote substitution

この質問はダッシュにのみ当てはまるようです。 ash、bash、ksh93ではこのエラーは発生しません。私のスクリプトにバックティック文字も含まれていないので、これは特に奇妙です。

5行目の末尾から二重引用符を削除すると、$?エラーは消えます。

私が愚かなことをしているのでしょうか、それともダッシュが誤動作するのでしょうか?私のスクリプトのエラーチェックレベルについて言及しないでください。

今、私たちはこれがUbuntuとDebianの最新バージョンに影響を与える非常に深刻なバグであることを確認しました。誰もが解決策を知っていますか?

答え1

以下は単純化されたテストケースです。

trap '
        trap    - HUP EXIT || exit "$?"
        kill -s HUP    "$$" || exit "$?" ' HUP INT
kill -HUP $$
$ dash dash-bug
dash-bug: 3: /home2/ahq/dash-bug: Syntax error: EOF in backquote substitution

参照されたコードの長さや内容を修正すると、バグが「修正」されたり、ランダムバイトが表示されるなど、さまざまな興味深い破損が発生する可能性があります。

これはダッシュ0.5.9以降修正されましたが、Debian 9.8 stable(stretch)、Ubuntu 18.04(bionic)、およびUbuntu 18.10(cosmic)のダッシュ0.5.8にはまだ存在するuse-after-freeバグが原因で発生します。

これは犯罪修正した:

commit 6c3f73bc536082fec38bd36e6c8a121033c68835
Author: Herbert Xu <[email protected]>
Date:   Thu Oct 2 08:26:06 2014 +0800

    [EVAL] Fix use-after-free in dotrap/evalstring

    The function dotrap calls evalstring using the stored trap string.
    If evalstring then unsets that exact trap string then we will end
    up using freed memory.

    This patch fixes it by making evalstring always duplicate the string
    before using it.

    Signed-off-by: Herbert Xu <[email protected]>

回避策は、トラップハンドラを関数に入れることです。次に、トラップが設定解除された後にコマンドが実行されず、解放された後にジョブ文字列を使用してみます。

sighandler(){
    trap - "$sig" EXIT || exit "$?"
    kill -s "$sig" "$$" || exit "$?"
}
for sig in HUP INT QUIT ALRM TERM; do
    trap "sig=$sig; sighandler" "$sig"
done

kill -s HUP "$$"

関連情報