NetBSD 10から11にしたらsambaがabortする問題

あるファイルサーバをNetBSD 10から11_RC5にしたら、samba (smbd, nmbd) があぼ~ん abort で core 吐いて死ぬ。でも、先に11系にした他のサーバでは動いてる。

gdbにcoreを食わせたところ、isspaceで死んでる。

samba-4.24.4/lib/util/util_str_common.c:

        /* sync the strings on first non-whitespace */
        while (1) {
                while (isspace((int)*psz1))
                        psz1++;
                while (isspace((int)*psz2))
                        psz2++;

そのときpsz1という変数名に何が入っていたかというと、smb.conf のセクションになってる共有名。でまあ、それが日本語 (UTF-8) なんだけど、int にキャストしてしまっているので負の値が渡っていたと。(他では日本語の共有名とか使ってないから動いてたんだな。)

じゃあなんで10では大丈夫だったかというと、

--- netbsd-10/src/lib/libc/gen/isctype.c
+++ netbsd-11/src/lib/libc/gen/isctype.c
…
+static int __noinline
+ctype_nasaldemon(const char *func, int c)
+{
+       char buf[128];
+
+       snprintf_ss(buf, sizeof(buf), "ctype(3) %s: invalid input: %d\n", func,
+           c);
+       (void)write(STDERR_FILENO, buf, strlen(buf));
+       if (allow_ctype_abuse())
+               return -1;
+       abort();
+}
+
+#define        CTYPE_CHECK(c) do                                                     \
+{                                                                            \
+       if (__predict_false(((c) != EOF && (c) < 0) || (c) > UCHAR_MAX))      \
+               return ctype_nasaldemon(__func__, c);                         \
+} while (0)
 
 #define _ISCTYPE_FUNC(name, bit) \
 int \
 is##name(int c) \
 { \
+       CTYPE_CHECK(c); \
        return (int)_ctype_tab_[c + 1] & (bit); \
 } \
 int \
 is##name ## _l(int c, locale_t loc) \
 { \
+       CTYPE_CHECK(c); \
        return (int)((_RUNE_LOCALE(loc)->rl_ctype_tab[c + 1]) & (bit)); \
 }

is##name がその後のマクロで isspace とかになるんだけど、11で CTYPE_CHECK というのが追加されている(10にはない)。んで、その中で範囲チェックをして、EOFでない負の数なので ctype_nasaldemonabort(); に辿り着くと。

え、10のときは負の方向に突き抜けてたんかい。

対処

上のソースで allow_ctype_abuse() というのがあるが、環境変数 LIBC_ALLOWCTYPEABUSE というのをセットしておくと abort は回避できるらしい。

まっとうな直し方は、

--- lib/util/util_str_common.c.orig     2026-01-21 00:42:54.186816700 +0900
+++ lib/util/util_str_common.c  2026-07-02 17:40:22.843239543 +0900
@@ -41,9 +41,9 @@

        /* sync the strings on first non-whitespace */
        while (1) {
-               while (isspace((int)*psz1))
+               while (isspace((unsigned char)*psz1))
                        psz1++;
-               while (isspace((int)*psz2))
+               while (isspace((unsigned char)*psz2))
                        psz2++;

                /*

……でしょうかね。