当 LC_CTYPE 设置为 C.UTF-8 时,Bash 在 Valgrind 中崩溃

Bash crashes in Valgrind when LC_CTYPE is set to C.UTF-8

提问人:charmoniumQ 提问时间:9/23/2023 最后编辑:charmoniumQ 更新时间:9/23/2023 访问量:46

问:

Bash 5.2 由于 malloc 中的断言失败而崩溃,但仅在 Valgrind 中运行时且仅在设置时崩溃。下面是一个示例输出:LC_CTYPE

$ path/to/env - foo=bar LC_CTYPE=C.UTF-8 path/to/valgrind path/to/bash -c 'echo ${foo#spam}'

...

malloc: subst.c:5331: assertion botched
free: called with unallocated block argument
Aborting...==2753214== 
==2753214== Process terminating with default action of signal 6 (SIGABRT): dumping core
==2753214==    at 0x48DFA8C: __pthread_kill_implementation (in /nix/store/aw2fw9ag10wr9pf0qk4nk5sxi0q0bn56-glibc-2.37-8/lib/libc.so.6)
==2753214==    by 0x4890C85: raise (in /nix/store/aw2fw9ag10wr9pf0qk4nk5sxi0q0bn56-glibc-2.37-8/lib/libc.so.6)
==2753214==    by 0x487A8B9: abort (in /nix/store/aw2fw9ag10wr9pf0qk4nk5sxi0q0bn56-glibc-2.37-8/lib/libc.so.6)
==2753214==    by 0x443AF9: programming_error (in /nix/store/vqvj60h076bhqj6977caz0pfxs6543nb-bash-5.2-p15/bin/bash)
==2753214==    by 0x4ACAC4: internal_free.constprop.0 (in /nix/store/vqvj60h076bhqj6977caz0pfxs6543nb-bash-5.2-p15/bin/bash)
==2753214==    by 0x450A5E: remove_pattern (in /nix/store/vqvj60h076bhqj6977caz0pfxs6543nb-bash-5.2-p15/bin/bash)
==2753214==    by 0x465D2B: parameter_brace_remove_pattern (in /nix/store/vqvj60h076bhqj6977caz0pfxs6543nb-bash-5.2-p15/bin/bash)
==2753214==    by 0x46023A: param_expand (in /nix/store/vqvj60h076bhqj6977caz0pfxs6543nb-bash-5.2-p15/bin/bash)
==2753214==    by 0x460CD9: expand_word_internal (in /nix/store/vqvj60h076bhqj6977caz0pfxs6543nb-bash-5.2-p15/bin/bash)
==2753214==    by 0x466C0D: shell_expand_word_list.constprop.0 (in /nix/store/vqvj60h076bhqj6977caz0pfxs6543nb-bash-5.2-p15/bin/bash)
==2753214==    by 0x467479: expand_words (in /nix/store/vqvj60h076bhqj6977caz0pfxs6543nb-bash-5.2-p15/bin/bash)
==2753214==    by 0x4361CE: execute_command_internal (in /nix/store/vqvj60h076bhqj6977caz0pfxs6543nb-bash-5.2-p15/bin/bash)

...

==2753214== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
/nix/store/a683qmhmrrzrwn8fmqh53yyylm7yn2hq-test.sh: line 2: 2753214 Aborted                 (core dumped) /nix/store/v45j2p2izb3pa2fxdw978bahhkb2ghza-toybox-0.8.10/bin/env - LC_CTYPE=C.UTF-8 /nix/store/14fg82n6grqhrd2algx31sv1kmgvz0gl-valgrind-3.21.0/bin/valgrind /nix/store/vqvj60h076bhqj6977caz0pfxs6543nb-bash-5.2-p15/bin/bash -c 'echo ${PATH#":"}'

(完整输出在这里)

${parameter#word}是这里描述的一种参数扩展。

指示的源代码行指向此处,但有问题的断言是否在 or ?freemalloc

尝试一些变化:

  • 在 Valgrind 之外,Bash 成功了(根本不崩溃)。
  • 保留 unset 或设置为 empty-string 会导致 Bash 成功(无崩溃);但是任何非空设置似乎都会导致崩溃。foofoo
  • 如果我们将该模式替换为 中确实存在的模式,则 Bash 崩溃,而不是 ;这两种情况都会导致崩溃,当模式与参数扩展匹配时,当它不匹配时,但在略有不同的位置。foosubst.c:5336subst.c:5331
  • 当未设置或设置为任何其他语言环境(包括不存在的语言环境)时,Bash 不会崩溃(尽管存在非致命无效)。LC_CTYPEfree()

我应该如何调试此问题?

关于可重复性的说明:

  • 因为我没有使用默认系统中的任何环境变量、二进制文件或库,所以我认为这在任何x86_64机器上都应该相当可重现。如果重要的话,我在 Linux 5.15.0-83-generic 上运行 Ubuntu 22.04.3。
  • 在这里创建了一个 Nix 薄片。如果您下载并下载到一个空目录,您应该能够键入并(希望)也崩溃。flake.nixflake.locknix run
巴什 马洛克· 瓦尔格林德

评论

0赞 Fravadona 9/23/2023
应该是什么区域设置?C.UTF-8
1赞 charmoniumQ 9/23/2023
我的理解是,它是某种“中性”语言环境,其中字符根据其 UTF-8 代码点进行排序。stackoverflow.com/questions/55673886/......
0赞 Kaz 9/23/2023
如果你必须问如何调试它,也许只需将其报告给 Bash 项目,并提供尽可能多的信息。

答:

1赞 Kaz 9/23/2023 #1

我会创建一个特殊的 Bash 版本,其中禁用了 Bash 的 malloc 包装,并尝试像以前一样在 Valgrind 下重现该问题。

您遇到了 Bash 本身正在自我诊断 malloc 问题的问题。它不会像 Valgrind 本身那样做得好。

Bash 的诊断是说它是在未分配的块上调用的。Valgrind 的类似诊断信息量更大。如果之前在该地址存在已分配的对象,Valgrind 将显示该对象,以及释放该对象的位置的回溯跟踪。free

Bash 的调试 malloc(参见 中的函数依赖于检查 freed 块中的一些标头信息来得出结论,它是双重释放的。这是不准确的。代码如下所示:internal_freelib/malloc/malloc.c

  if (p->mh_alloc != ISALLOC)
    {
      if (p->mh_alloc == ISFREE)
        xbotch (mem, ERR_DUPFREE,
                _("free: called with already freed block argument"), file, line);
      else
        xbotch (mem, ERR_UNALLOC,
                _("free: called with unallocated block argument"), file, line);
    }

如果在块头中发现一个魔术字节,而该魔术字节不是 (即 ),它会专门检查 .如果不是 (),则它会发出您看到的诊断。ISALLOC0xF7ISFREEISFREE0x57

这很容易出现误报,因为当标头中的魔术代码被破坏为不是 256 个可能值中的两个可能值之一的值时,就会发生误报。

我们不能合理地认为这是一个双重自由问题。这很可能是腐败,如果它重现,Valgrind 的分配器在诊断它方面会做得更好。