dash:当我的脚本甚至不包含反引号时,为什么我会收到错误“语法错误:反引号替换中的 EOF”?

Har*_*her 1 shell dash quoting

#!/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 "$?"
Run Code Online (Sandbox Code Playgroud)

这是我向脚本发送 SIGINT 时发生的情况

user@hostname:/tmp$ ./script.sh
^C./script.sh: 3: ./script.sh: Syntax error: EOF in backquote substitution
Run Code Online (Sandbox Code Playgroud)

这个问题似乎是针对 dash 的。在 ash、bash 和 ksh93 上我没有收到此错误。这特别奇怪,因为我的脚本甚至不包含反引号字符。

如果我删除第 5 行末尾的双引号,$?错误就会消失。

我是在做一些愚蠢的事情还是dash行为不当?请不要对我的脚本中的错误检查级别发表评论。

我们现在已经确定这是一个非常严重的错误,甚至影响现代版本的 Ubuntu 和 Debian。有谁知道解决方法?

小智 5

这是一个简化的测试用例:

trap '
        trap    - HUP EXIT || exit "$?"
        kill -s HUP    "$$" || exit "$?" ' HUP INT
kill -HUP $$
Run Code Online (Sandbox Code Playgroud)
$ dash dash-bug
dash-bug: 3: /home2/ahq/dash-bug: Syntax error: EOF in backquote substitution
Run Code Online (Sandbox Code Playgroud)

修改引用代码的长度或内容可能会“修复”错误或产生不同且有趣的损坏,随机字节会突然出现。

这是由释放后使用错误引起的,该错误自 dash 0.5.9 起已修复,但在 Debian 9.8 stable (stretch)、Ubuntu 18.04 (bionic) 和 Ubuntu 18.10 (cosmic) 的 dash 0.5.8 中仍然存在。

这是修复它的提交

commit 6c3f73bc536082fec38bd36e6c8a121033c68835
Author: Herbert Xu <herbert@gondor.apana.org.au>
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 <herbert@gondor.apana.org.au>
Run Code Online (Sandbox Code Playgroud)

解决方法是将陷阱处理程序放入函数中 - 以便在陷阱取消设置后不会运行任何命令,并在释放后尝试使用操作字符串:

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 "$$"
Run Code Online (Sandbox Code Playgroud)